/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "queue.h"
#include "swtimer.h"
#include "swlog.h"
#include "flash_if.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#pragma pack(1)
typedef union {
 char xbyte[1024+18];//1042
 struct {
     uint16_t header;   /* 0x2355 */
     uint16_t length;  /*funcCode+packTotal+packCounter+data*/
     uint16_t devAddress;  /* 0x1234 */
     uint16_t functionCode;   /*0x0100*/
     uint16_t packTotal;
     uint16_t packCounter;
	   uint16_t datalength;
     uint8_t  data[1024];
     uint16_t checkSum;
     uint16_t tail;   /* 0x0D0A */
 }SIG;
}boot_protocol;

#pragma pack(1)
typedef struct {
	uint8_t max_size_per_time : 2;
	uint8_t reserve : 6;
}boot_param;

#pragma pack(1)
typedef struct {
	uint8_t sw_major_version;
	uint8_t sw_sub_version;
	uint8_t hw_major_version;
	uint8_t hw_sub_version;
}boot_handshake_ack;



typedef enum {
	BOOT_PACKET_TYPE_HANDSHAKE_REQ = 0X0,
	BOOT_PACKET_TYPE_HANDSHAKE_ACK,
	BOOT_PACKET_TYPE_SEND_BLOCK,
	BOOT_PACKET_TYPE_SEND_BLOCK_ACK,
	BOOT_PACKET_TYPE_SEND_BLOCK_RETRANSMIT_REQ
}boot_packet_type;
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
SoftwareTimer timers[2];
Queue uart1_queue;
Queue uart2_queue;

uint8_t u1_buf[QUEUE_MAX_SIZE];
uint8_t u2_buf[QUEUE_MAX_SIZE];

unsigned char usart1_ch;
unsigned char usart2_ch;
/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim6;
TIM_HandleTypeDef htim7;

UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM6_Init(void);
static void MX_TIM7_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
int UsartSend_callback_usart1(const unsigned char *pData,const unsigned short len)
{
  HAL_UART_Transmit(&huart1, pData, len, 0xFFFFF);
  return 1;
}
int UsartSend_callback_usart2(const unsigned char *pData,const unsigned short len)
{
  HAL_UART_Transmit(&huart2, pData, len, 0xFFFFF);
  return 1;
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart == &huart1)
	{
		queue_enqueue(&uart1_queue, usart1_ch);
		HAL_UART_Receive_IT(&huart1, &(usart1_ch), 1);
	}
	else if(huart == &huart2)
	{
		queue_enqueue(&uart2_queue, usart2_ch);
		HAL_UART_Receive_IT(&huart2, &(usart2_ch), 1);
	}

}

//led
//led
typedef void(*init)(GPIO_TypeDef* port, uint16_t pin);
typedef void(*on)(GPIO_TypeDef* port, uint16_t pin);
typedef void(*off)(GPIO_TypeDef* port, uint16_t pin);

void hal_led_init(GPIO_TypeDef* port, uint16_t pin)
{
  HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET);
}

void hal_led_on(GPIO_TypeDef* port, uint16_t pin)
{
  HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET);
}

void hal_led_off(GPIO_TypeDef* port, uint16_t pin)
{
  HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET);
}

typedef struct 
{
    GPIO_TypeDef* port;
    uint16_t pin;
    init led_init;
    on led_on;
    off led_off;
    uint8_t state;
} led_control;

led_control led_ctrl[2] = {
	{
    .port = GPIOF,
    .pin = led0_Pin,
    .led_init = hal_led_init,
    .led_on = hal_led_on,
    .led_off = hal_led_off,
    .state = 0x00
	},
	{
    .port = GPIOF,
    .pin = led1_Pin,
    .led_init = hal_led_init,
    .led_on = hal_led_on,
    .led_off = hal_led_off,
    .state = 0x00
	}
};

void led_control_init(led_control* ctrl, uint8_t count)
{
    for (uint8_t i = 0; i < count; i++)
    {
        ctrl[i].led_init(ctrl[i].port, ctrl[i].pin);
    }
}

void led_control_toggle(led_control* ctrl, uint8_t count)
{
    for (uint8_t i = 0; i < count; i++)
    {
        if (ctrl[i].state == 0x00)
        {
            ctrl[i].led_on(ctrl[i].port, ctrl[i].pin);
            ctrl[i].state = 0x01;
        }
        else
        {
            ctrl[i].led_off(ctrl[i].port, ctrl[i].pin);
            ctrl[i].state = 0x00;
        }
    }
}

uint8_t led_control_state(led_control* ctrl, uint8_t index)
{
    if (index < 2) 
    {
        return ctrl[index].state;
    }
    return 0xFF; 
}



typedef void (*pFunction)(void);

void jumptoapplication(uint32_t app_address) {
	pFunction JumpToApp;
	uint32_t stack_pointer;
	
	//1.disable global irq
  __disable_irq();	
	
	//2.reset status
	SysTick->CTRL = 0;		//close systick 
	SysTick->VAL = 0;			//clear systick
	HAL_RCC_DeInit();			//RESET rcc
	HAL_DeInit(); 				//reset peripheral
	
	//3.check stack pointer
	if ((*(volatile uint32_t*)app_address & 0x2FFE0000) != 0x20000000) {
		return;
	}
	//4.set msp
	stack_pointer = *(volatile uint32_t*)app_address;
	__set_MSP(stack_pointer);
	
	//5.function reset handler
	JumpToApp = (pFunction)(*(volatile uint32_t*)(app_address + 4));
	
	
	//6.data sync and clear instruction
	__DSB(); 
	__ISB(); 
	JumpToApp();
	
	while(1);
}

//revhandler
#define BOOT_BUF_MAX (1024*2U)
#define HANDLE_PROCESS_COUNT_MAX 4U 
#define HANDLE_PROCESS_TIMEOUT_MAX 4U
#define BOOT_DEV_ADDRESS	(uint16_t)0x1234U

#define HIGH_BYTE(addr) ((uint8_t)(((addr) >> 8) & 0xFF))
#define LOW_BYTE(addr)  ((uint8_t)((addr) & 0xFF))
#define LB(value) \
    (((value >> 8) & 0xFF) | ((value & 0xFF) << 8))



boot_protocol boot_buf;
boot_param boot_para;
boot_handshake_ack handshake_ack = {0,1,0,1};			//sw: 0.1v hw:0.1v
boot_packet_type current_status = BOOT_PACKET_TYPE_HANDSHAKE_REQ;
uint32_t boot_len;
uint16_t dev_address;
uint16_t functionCode;
uint16_t data_max_size = 1024;
uint8_t timeout_count = 0;
uint16_t current_packtotal = 0;
uint16_t current_packcounter = 0;
uint16_t update_trigger_flag = 0;
uint16_t update_success_flag = 0;
//boot_ack function
uint8_t boot_ack_buf[1024*2] = {0};
boot_protocol protocol_send = {0};
//boot_parse_send_block_msg function
uint16_t packtotal_count = 0;
uint32_t flash_offset = 0;
uint32_t start = 0;
uint32_t end = 0;


typedef int (*handler_process) (uint8_t ch) ;
typedef void (*handler_cb) (void);

typedef struct 
{
  handler_process handler_process[HANDLE_PROCESS_COUNT_MAX];
	handler_cb			handler_cb[HANDLE_PROCESS_COUNT_MAX];
  uint8_t handler_process_count;
}rev_handler_ops;

typedef struct 
{
  Queue *queue;
  rev_handler_ops* ops;
}rev_handler;

int boot_process(uint8_t ch);
void boot_send_machine(void);
void boot_cb(void);
int rev_handler_process(rev_handler *handler);
void devaddr_chk_machine(uint8_t* flag);
void boot_parse_machine(void);

rev_handler_ops u1_handler_ops = {.handler_process = {boot_process}, .handler_cb = {boot_cb}, .handler_process_count = 1};
rev_handler u1_rev_handler = { .ops = &u1_handler_ops };

int rev_handler_process(rev_handler *handler)
{
  Queue* q = handler->queue;
	int ret = 0;
  
  uint8_t ch;
  if(q == NULL) return -1;          //queue is null
  if(queue_is_empty(q)) return -2;  //queue is empty
  
  while(!queue_is_empty(q))
  {
    ch = queue_dequeue(q);
	
		if(handler->ops->handler_process_count > HANDLE_PROCESS_COUNT_MAX)	
		{
			handler->ops->handler_process_count = HANDLE_PROCESS_COUNT_MAX;
		}
		
    for(uint8_t i=0; i < (handler->ops->handler_process_count); i++)
    {
      ret = handler->ops->handler_process[i](ch);
			if(ret == 1)
			{
				if(handler->ops->handler_cb[i] != NULL)
				{
					handler->ops->handler_cb[i]();
				}
			}
    }
		
  }

  return ret;
}

uint32_t checksum_calculate(const uint8_t *data, size_t length)
{
	uint32_t checksum = 0;
	for(size_t i = 0; i < length; i++)
	{
		checksum += data[i];
	}
	
	return checksum;
}

void RevCallbacku1(void)
{
	if(update_success_flag == 0)
	{
		rev_handler_process(&u1_rev_handler);		//rev_process 
		boot_send_machine();						//send_process	
	}else if(update_success_flag == 1) {
		stopSoftwareTimer(&timers[0]);
		jumptoapplication(start);
		
	}else {}
}


void boot_cb()
{
	uint8_t flag;
	
	devaddr_chk_machine(&flag);
	
	switch(flag)
	{
		case 0x1:
			boot_parse_machine();
			break;
		default:
			break;
	}
}

int boot_process(uint8_t ch)
{
	static uint8_t *buf_ptr = (uint8_t *)&boot_buf;
	static uint16_t idx = 0;
	static uint8_t stat = 0;
	static uint16_t total_length = 0;
	
	switch (stat) {
		case 0:
			if (idx == 0 && ch == 0x23) 
			{
					buf_ptr[idx++] = ch;
			} 
			else if (idx == 1 && ch == 0x55) 
			{
					buf_ptr[idx++] = ch;
					stat = 1;
			} 
			else 
			{
					idx = 0;
			}			
		break;
		case 1:
			buf_ptr[idx++] = ch;
			if (idx == 4) 
			{  
					if (boot_buf.SIG.length <= 1032) 		//1024+8 const length only in send block // in other packet
					{
							total_length = boot_buf.SIG.length + 10; 
							stat = 2;
					} 
					else 
					{
							idx = 0;
							stat = 0;
					}
			}
			break;			
		case 2:
			buf_ptr[idx++] = ch;
			if(idx >= total_length - 4) 
			{ 
					buf_ptr += sizeof(boot_buf.SIG.data) - boot_buf.SIG.datalength;	//filled utill checksum 
					stat = 3;
			}
			break;	
			
		case 3:
			buf_ptr[idx++] = ch;
			if(idx ==  total_length - 2)
			{
				uint16_t received_checksum = boot_buf.SIG.checkSum;
				uint16_t calculated_checksum = checksum_calculate(
                    (uint8_t *)&boot_buf.SIG.functionCode, 
                    boot_buf.SIG.length);		
				if (received_checksum == calculated_checksum) 
				{
						stat = 4;
				} 
				else 
				{
						idx = 0;
						stat = 0;
				}				
			}
			break;
		case 4:
			if (idx == total_length - 1 && ch == 0x0D) 
			{
				buf_ptr[idx++] = ch;
			}
			else if(idx == total_length && ch == 0x0A)
			{
				buf_ptr[idx++] = ch;
				boot_len = idx;
				idx = 0;
				stat = 0;
				return 1;
			}
			else
			{
				idx = 0;
				stat = 0;
			}
			break;
		default:
			idx = 0;
			stat = 0;
			break;
	}
	return 0;
}


void devaddr_chk_machine(uint8_t *flag)
{
	
	switch(boot_buf.SIG.devAddress)
	{
		case 0x1234:
				*flag = 0x1;
				dev_address = 0x1234;
			break;
		default:
				*flag = 0x00;
				dev_address = 0x0000;
			break;
	}
}

int boot_ack(boot_protocol* protocol)
{
	memset(boot_ack_buf, 0, sizeof(boot_ack_buf));
	
	memcpy(boot_ack_buf, protocol, protocol->SIG.length + 6);
	memcpy(boot_ack_buf + protocol->SIG.length + 6, &protocol->SIG.checkSum, 4);
	
	UsartSend_callback_usart1(boot_ack_buf, protocol->SIG.length + 10);
	
	return 1;
}

int boot_parse_handshake_req(void)
{
	if(boot_buf.SIG.datalength == sizeof(boot_param))
	{
		memcpy(&boot_para, boot_buf.SIG.data, sizeof(boot_param));
		
		uint8_t mode = boot_para.max_size_per_time & ((1<<2)-1);
		
		if(mode == 0x00)
		{
			data_max_size = 1024;
		}
		else if(mode == 0x01)
		{
			data_max_size = 512;
		}
		else if(mode == 0x02)
		{
			data_max_size = 256;
		}
		else if(mode == 0x03)
		{
			data_max_size = 128;
		}
		else
		{}
	}
	else
	{
		return 0;
	}
	
	return 1;
}


int boot_parse_send_block_msg()
{
	HAL_StatusTypeDef ret;
	if(boot_buf.SIG.datalength == data_max_size)
	{
			if(update_trigger_flag == 1)
			{
				update_trigger_flag = 0;
				//judge setup app1 or app2 ?
				if(1) {
					start = flash_update_tbl[2].SectorStartID;
					end = flash_update_tbl[2].SectorEndID;
				}else {
					start = flash_update_tbl[3].SectorStartID;
					end = flash_update_tbl[3].SectorEndID;
				}
				flash_offset = 0;
				packtotal_count = boot_buf.SIG.packCounter;
				
				ret = FLASH_EraseSectors(start, end - start);
				if(ret != HAL_OK)
				{
					return -1;
				}
			}
			current_packcounter = boot_buf.SIG.packCounter;
			current_packtotal = boot_buf.SIG.packTotal;
		
			ret = FLASH_WriteBuffer((f4xx_flash_tbl[start].StartAddress + flash_offset), (uint32_t*)boot_buf.SIG.data, data_max_size/4);
			flash_offset += data_max_size;
			packtotal_count -= 1;
			if(ret != HAL_OK)
			{
				return -2;
			}

		return 0;
	}else {return -3;}
}

int boot_send_handshake_ack(void)
{
	int ret;
	
	protocol_send.SIG.devAddress = LB(0x1234);
	protocol_send.SIG.functionCode = BOOT_PACKET_TYPE_HANDSHAKE_ACK;
	protocol_send.SIG.length = sizeof(handshake_ack) + 8;
	protocol_send.SIG.packTotal = 1;
	protocol_send.SIG.packCounter = 0;
	protocol_send.SIG.header = LB(0x2355);
	protocol_send.SIG.tail = LB(0x0d0a);
	protocol_send.SIG.datalength = sizeof(handshake_ack);
	memcpy(protocol_send.SIG.data, &handshake_ack, sizeof(boot_handshake_ack));
	protocol_send.SIG.checkSum = checksum_calculate((uint8_t*)&protocol_send.SIG.functionCode, protocol_send.SIG.length);
	
	ret = boot_ack(&protocol_send);
	
	return ret;
}




int boot_send_block_ack(void)
{
	int ret;
	
	protocol_send.SIG.devAddress = LB(0x1234);
	protocol_send.SIG.functionCode = BOOT_PACKET_TYPE_SEND_BLOCK_ACK;
	protocol_send.SIG.length = 2 + 8;
	protocol_send.SIG.packTotal = 1;
	protocol_send.SIG.packCounter = 0;
	protocol_send.SIG.header = LB(0x2355);
	protocol_send.SIG.tail = LB(0x0d0a);
	protocol_send.SIG.datalength = 2;
	protocol_send.SIG.data[0] = current_packtotal;
	protocol_send.SIG.data[1] = current_packcounter; 
	protocol_send.SIG.checkSum = checksum_calculate((uint8_t*)&protocol_send.SIG.functionCode, protocol_send.SIG.length);
	
	ret = boot_ack(&protocol_send);
	
	return ret;
}

int is_boot_complete()
{
	if(boot_buf.SIG.packCounter == boot_buf.SIG.packTotal - 1 && packtotal_count == 0)
	{
		return 1;
	}else {
		return 0;
	}
	 
}


int boot_send_block_retransmit_req(void)
{
	int ret;
	
	protocol_send.SIG.devAddress = LB(0x1234);
	protocol_send.SIG.functionCode = BOOT_PACKET_TYPE_SEND_BLOCK_RETRANSMIT_REQ;
	protocol_send.SIG.length = 2 + 8;
	protocol_send.SIG.packTotal = 1;
	protocol_send.SIG.packCounter = 0;
	protocol_send.SIG.header = LB(0x2355);
	protocol_send.SIG.tail = LB(0x0d0a);
	protocol_send.SIG.datalength = 2;
	protocol_send.SIG.data[0] = current_packtotal;
	protocol_send.SIG.data[1] = current_packcounter; 
	protocol_send.SIG.checkSum = checksum_calculate((uint8_t*)&protocol_send.SIG.functionCode, protocol_send.SIG.length);
	
	return ret;	
}



SoftwareTimer timeout_timer;
SoftwareTimer handshake_timer;
void boot_send_machine(void)
{
	switch(current_status)
	{
		case BOOT_PACKET_TYPE_HANDSHAKE_REQ:
			if(isSoftwareTimerTimeout(&handshake_timer))
			{
				if(1)
				{
					start = flash_update_tbl[2].SectorStartID;
					end = flash_update_tbl[2].SectorEndID;
				}else {
					start = flash_update_tbl[3].SectorStartID;
					end = flash_update_tbl[3].SectorEndID;
				}
				jumptoapplication(start);
			}

			break;
		case BOOT_PACKET_TYPE_HANDSHAKE_ACK:
			boot_send_handshake_ack();
			current_status = BOOT_PACKET_TYPE_SEND_BLOCK;
			initSoftwareTimer(&timeout_timer, 5*1000, TIMER_TYPE_SINGLE, NULL);
			startSoftwareTimer(&timeout_timer);
			update_trigger_flag = 1;
			break;
		case BOOT_PACKET_TYPE_SEND_BLOCK:
			if(isSoftwareTimerTimeout(&timeout_timer))			//20s wait send block
			{
				//do retransmit operation
				log_warning("wait timeout");
				boot_send_block_retransmit_req();
				
				startSoftwareTimer(&timeout_timer);						//if retransmit -> send block  = restart timer
				current_status = BOOT_PACKET_TYPE_SEND_BLOCK_RETRANSMIT_REQ;
				timeout_count = 1;
			}
			break;
		case BOOT_PACKET_TYPE_SEND_BLOCK_ACK:
			//do send block ack
			boot_send_block_ack();
			if(is_boot_complete() == 0)
			{
				startSoftwareTimer(&timeout_timer);
				current_status = BOOT_PACKET_TYPE_SEND_BLOCK;
			}else {
				current_status = BOOT_PACKET_TYPE_HANDSHAKE_REQ;
				update_success_flag = 1;
			}
			break;
		case BOOT_PACKET_TYPE_SEND_BLOCK_RETRANSMIT_REQ:
			//do retransmit operation 
			boot_send_block_retransmit_req();
		
			if(isSoftwareTimerTimeout(&timeout_timer))
			{
				if(timeout_count >= 4) {
					log_error("timeout count out of range, update failed");
					timeout_count = 0;
					current_status = BOOT_PACKET_TYPE_HANDSHAKE_REQ;
				}else {
					startSoftwareTimer(&timeout_timer);
					current_status = BOOT_PACKET_TYPE_SEND_BLOCK_RETRANSMIT_REQ;
					timeout_count++;
				}
			}
			break;
		default: 
			current_status = BOOT_PACKET_TYPE_HANDSHAKE_REQ;
			break;
	}
	
}


void boot_parse_machine(void)
{
	boot_packet_type type = (boot_packet_type)boot_buf.SIG.functionCode;
	int ret = -1;
	
	switch(type)
	{
		case BOOT_PACKET_TYPE_HANDSHAKE_REQ:							//master send
			ret = boot_parse_handshake_req();
			functionCode = BOOT_PACKET_TYPE_HANDSHAKE_REQ;
			if(ret == 1) {
				current_status = BOOT_PACKET_TYPE_HANDSHAKE_ACK;
			}else {
				current_status = BOOT_PACKET_TYPE_HANDSHAKE_REQ;
			}
			break;

		case BOOT_PACKET_TYPE_SEND_BLOCK:									
			functionCode = BOOT_PACKET_TYPE_SEND_BLOCK;
			boot_parse_send_block_msg();
			current_status = BOOT_PACKET_TYPE_SEND_BLOCK_ACK;
			break;

		default:
			break;
	}
}

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM6_Init();
  MX_TIM7_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_UART_Receive_IT(&huart1, &(usart1_ch), 1);
  HAL_UART_Receive_IT(&huart2, &(usart2_ch), 1);
  led_control_init(led_ctrl, 2);
	
  initSoftwareTimer(&timers[0], 100, TIMER_TYPE_PERIODIC, RevCallbacku1);
  initSoftwareTimer(&handshake_timer, 20*1000, TIMER_TYPE_SINGLE, NULL);
  u1_rev_handler.queue = &uart1_queue;
  queue_init(&uart1_queue, u1_buf, QUEUE_MAX_SIZE);
	
	log_init();
	log_set_level(LOG_LEVEL_INFO);
	log_info("boot start");
	
  //startSoftwareTimer(&timers[0]);
  startSoftwareTimer(&handshake_timer);
  boot_send_block_ack();
//  start = flash_update_tbl[2].SectorStartID;
//  end = flash_update_tbl[2].SectorEndID;
//  HAL_StatusTypeDef ret = FLASH_EraseSectors(start, end - start);
//  if(ret != HAL_OK)
//  {
//	return -1;
//  }

//  uint8_t data[512] = {0};

//  for(size_t i=0; i<512; i++)
//  {
//	data[i] = i;
//  }

//  FLASH_WriteBuffer(f4xx_flash_tbl[start].StartAddress, (uint32_t*)data, 512/4);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		
	//checkSoftwareTimers(timers, 1);
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief TIM6 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM6_Init(void)
{

  /* USER CODE BEGIN TIM6_Init 0 */

  /* USER CODE END TIM6_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM6_Init 1 */

  /* USER CODE END TIM6_Init 1 */
  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 168;
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 65535;
  htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM6_Init 2 */

  /* USER CODE END TIM6_Init 2 */

}

/**
  * @brief TIM7 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM7_Init(void)
{

  /* USER CODE BEGIN TIM7_Init 0 */

  /* USER CODE END TIM7_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM7_Init 1 */

  /* USER CODE END TIM7_Init 1 */
  htim7.Instance = TIM7;
  htim7.Init.Prescaler = 168;
  htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim7.Init.Period = 65535;
  htim7.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim7) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim7, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM7_Init 2 */

  /* USER CODE END TIM7_Init 2 */

}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
  * @brief USART2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOF, led1_Pin|led0_Pin, GPIO_PIN_SET);

  /*Configure GPIO pins : led1_Pin led1F10_Pin */
  GPIO_InitStruct.Pin = led1_Pin|led0_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
